#include "android_env.h"

#define LOG(...) __android_log_print(ANDROID_LOG_DEBUG,"&&& POS jnihelper",__VA_ARGS__)

JavaVM *gJavaVM = NULL;

int initJavaVM(JNIEnv *env)
{
    if (gJavaVM == NULL)
    {
        return (*env)->GetJavaVM(env, &gJavaVM);
    }
    return 0;
}

JNIEnv *getJNIEnv(JavaVM *pJavaVM)
{
    if (gJavaVM == NULL)
    {
        return NULL;
    }
    JavaVMAttachArgs lJavaVMAttachArgs;
    lJavaVMAttachArgs.version = JNI_VERSION_1_4;
    lJavaVMAttachArgs.name = "NativeCallBack";
    lJavaVMAttachArgs.group = NULL;
    JNIEnv *lEnv;
    if ((*pJavaVM)->AttachCurrentThread(pJavaVM, &lEnv, &lJavaVMAttachArgs)
        != JNI_OK)
    {
        lEnv = NULL;
    }
    return lEnv;
}

JNIEnv *getEnvInfo(int *detach)
{
    JNIEnv *env = NULL;
    if (gJavaVM == NULL)
    {
        return NULL;
    }
    if ((*gJavaVM)->GetEnv(gJavaVM, (void **) &env, JNI_VERSION_1_4) != JNI_OK)
    {
        env = getJNIEnv(gJavaVM);
        //envInfo->detach = 1;
        *detach = 1;
    }
    else
    {
        //envInfo->detach = 0;
        *detach = 0;
    }
    return env;
}

int detach_thread(int needDetach)
{
    if (gJavaVM == NULL)
    {
        return -1;
    }
    if (needDetach)
    {
        return (*gJavaVM)->DetachCurrentThread(gJavaVM);
    }
    return 1;
}

void dump_buffer2(char *head, char *buf, int length)
{
    LOG("len = %d", length);
    int i = 0;
    int dump_buffer_len = length * 4 + 1;
    char *dump_buffer = malloc(dump_buffer_len);

    memset(dump_buffer, 0, dump_buffer_len);

    while (i < length)
    {
        sprintf(dump_buffer + i * 4, "%02x  ", buf[i]);
        i++;
    }

    LOG("%s %s", head, dump_buffer);
    free(dump_buffer);

    return;
}

void jbyteArray_to_u8(JNIEnv *e, jbyteArray buffer, unsigned char *dest)
{
    jbyte *array = NULL;
    size_t length = 0;

    if (buffer == NULL)
    {
        return;
    }

    array = (*e)->GetByteArrayElements(e, buffer, NULL);
    if (array == NULL)
    {
        return;
    }

    length = (size_t) (*e)->GetArrayLength(e, buffer);
    memcpy(dest, array, (size_t) length);

    (*e)->ReleaseByteArrayElements(e, buffer, array, 0);
}

void jbyteArray_to_s8(JNIEnv *e, jbyteArray buffer, char *dest)
{
    jbyte *array = NULL;
    size_t length = 0;

    if (buffer == NULL)
    {
        return;
    }

    array = (*e)->GetByteArrayElements(e, buffer, NULL);
    if (array == NULL)
    {
        return;
    }

    strcpy(dest, (char *) array);

    (*e)->ReleaseByteArrayElements(e, buffer, array, 0);
}

unsigned char *jbyteArray_to_charArray(JNIEnv *e, jbyteArray buffer, int length)
{
    if (buffer == NULL)
    {
        LOG("buffer = null");
        return NULL;
    }
    jbyte *array;
    jboolean *buf;
    array = (*e)->GetByteArrayElements(e, buffer, NULL);
    if (array == NULL)
    {
        //LOG("jbyteArray_to_charArray: GetCharArrayElements error.");
        return NULL;
    }
    buf = (jboolean *) calloc(length, sizeof(jboolean));
    if (buf == NULL)
    {
        //LOG("jbyteArray_to_charArray: calloc error.");
        return NULL;
    }
    int i;
    for (i = 0; i < length; i++)
    {
        *(buf + i) = (jboolean) (*(array + i));
        //LOG("buf[%d]=%x\n", i, *(buf+i));
    }
    (*e)->ReleaseByteArrayElements(e, buffer, array, 0);
    return buf;
}


jbyteArray chars_to_jbyteArray(JNIEnv *env, char *data, int len)
{
    //dump_buffer2("chars_to_jbyteArray data =", data, len);
    jbyteArray jbyteArray1 = (*env)->NewByteArray(env, len);
    (*env)->SetByteArrayRegion(env, jbyteArray1, 0, len, (jbyte *) data);
    return jbyteArray1;
}

jintArray chars_to_jintarray(JNIEnv *env, int *data, int len)
{
    jintArray jintArray1 = (*env)->NewIntArray(env, len);
    (*env)->SetIntArrayRegion(env, jintArray1, 0, len, data);
    return jintArray1;
}

jstring stoJstring(JNIEnv *env, const unsigned char *buffer, unsigned char bufferLen)
{
    return (*env)->NewStringUTF(env, (char *) buffer);
}


void jstringToString(JNIEnv *env, jstring jstr, char *outStr, int len)
{
    if (jstr == NULL)
    {
        return;
    }

    int iCopyLen = 0;

    memset(outStr, 0, len);
    const char *nativeString = (*env)->GetStringUTFChars(env, jstr, 0);
    iCopyLen = (strlen(nativeString) >= len) ? len : (strlen(nativeString));
    memcpy(&outStr[0], &nativeString[0], iCopyLen);
    (*env)->ReleaseStringUTFChars(env, jstr, nativeString);
}

void jintArrayToChars(JNIEnv *e, jintArray jintArray1, int *outStr, int len)
{
    if (jintArray1 == NULL)
    {
        return;
    }
    jint *array;
    array = (*e)->GetIntArrayElements(e, jintArray1, NULL);
    if (array == NULL)
    {
        return;
    }
    int i;
    for (i = 0; i < len; i++)
    {
        *(outStr + i) = (jboolean) (*(array + i));
        //LOG("buf[%d]=%x\n", i, *(buf+i));
    }
    (*e)->ReleaseIntArrayElements(e, jintArray1, array, 0);
}

void jbyteArrayToChars(JNIEnv *e, jbyteArray jbyteArray1, char *outStr, int len)
{
    if (jbyteArray1 == NULL)
    {
        LOG("jbyteArray1 = null");
        return;
    }
    jbyte *array;
    array = (*e)->GetByteArrayElements(e, jbyteArray1, NULL);
    if (array == NULL)
    {
        LOG("jbyteArray_to_charArray: GetCharArrayElements error.");
        return;
    }
    int arrayLen = (*e)->GetArrayLength(e, jbyteArray1);
    int copyLen;
    if (arrayLen >= len)
    {
        copyLen = len;
    }
    else
    {
        copyLen = arrayLen;
    }
    int i;
    for (i = 0; i < copyLen; i++)
    {
        *(outStr + i) = (jboolean) (*(array + i));
    }
    (*e)->ReleaseByteArrayElements(e, jbyteArray1, array, 0);
}
